#include "httpTools.h"
#include "umapi_os.h"
#include "umapi_libc.h"
#include "umapi_socket.h"
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavformat/version.h"
#include "libavcodec/avcodec.h"
#include "libavutil/avstring.h"
#include "umlog.h"
#include "epollTools.h"

#define TARGET "HTTPTOOLS"
#define DEBUGLEVEL httptoolslevel

static UM_S32 httptoolslevel = 0;
UM_VOID setHttpToolsDebug(UM_S32 level)
{
	httptoolslevel = level;
}
int readIntByKey(UM_U8 *key, HttpHeaders *h)
{
	struct umapi_list_head *pos, *n;
	umapi_list_for_each_safe(pos,n,&h->h)
	{
		KV *kv = umapi_list_entry(pos,KV,h);
		if(umapi_strcmp(kv->key, key)==0)
		{
			return umapi_atoi(kv->value);
		}
	}		
	return 0;
}
UM_CHAR* readStringByKey(UM_U8 *key, HttpHeaders *h, UM_CHAR *value)
{
	struct umapi_list_head *pos, *n;
	umapi_list_for_each_safe(pos,n,&h->h)
	{
		KV *kv = umapi_list_entry(pos,KV,h);
		if(umapi_strcmp(kv->key, key)==0)
		{
			umapi_sprintf(value, "%s", kv->value);
			return kv->value;
		}
	}		
	return UM_NULL;
}

void parseLine(AVFormatContext *s,
                        HttpHeaders *reply, const char *buf,
                        UM_S32 *rt, const char *method)
{
    const char *p;
    p = buf;
    if (av_stristart(p, "Content-Length:", &p)) {
        reply->contentLen = strtol(p, NULL, 10);
    } 
	UM_CHAR *ptmp = umapi_strstr(buf, ": ");
	if(ptmp)
	{
		KV *pkv = (KV*)umapi_malloc(sizeof(KV));
		if(!pkv)
		{
			LOGS("malloc KV fail");
			return ;
		}
		pkv->key = (UM_CHAR *)umapi_malloc(ptmp - buf + 1);
		if(!pkv->key)
		{
			LOGS("malloc KV.key fail");
			umapi_free(pkv);
			return ;
		}
		umapi_memcpy(pkv->key, buf, ptmp - buf);
		pkv->key[ptmp - buf] = '\0';
		pkv->value = (UM_CHAR *)umapi_malloc(umapi_strlen(buf) - (ptmp - buf) - 1);
		if(!pkv->value)
		{
			LOGS("malloc KV.value fail");
			umapi_free(pkv->key);
			umapi_free(pkv);
			return ;
		}
		umapi_memcpy(pkv->value, ptmp+2, umapi_strlen(buf) - (ptmp - buf) - 2);
		pkv->value[umapi_strlen(buf) - (ptmp - buf) - 2] ='\0';
//		DEBUG("key:%s,value:%s", pkv->key, pkv->value);
		umapi_list_add(&pkv->h, &reply->h);
	}
}
UM_VOID decBufferToHeaders(UM_U8 *buff, HttpHeaders *h)
{
	
	UM_CHAR* p = buff, *p1, *p2;
	UM_S32 len;
	char cmd[32];
	char url[1024];
	char version[32];
	char line[1024];
	getWord(cmd, sizeof(cmd), &p);
	getWord(url, sizeof(url), &p);
	getWord(version, sizeof(version), &p);

	av_strlcpy(h->method, cmd, sizeof(h->method));
	av_strlcpy(h->url, url, sizeof(h->url));
	av_strlcpy(h->version, version, sizeof(h->version));
	umapi_list_create(&h->h);
	LOGI("recv buff:%s,method:%s, url:%s, version:%s", buff, h->method, h->url, h->version);
	while (*p != '\n' && *p != '\0')
		p++;
	if (*p == '\n')
		p++;
	while (*p != '\0') {
		p1 = memchr(p, '\n', (char *)buff - p);
		if (!p1)
			break;
		p2 = p1;
		if (p2 > p && p2[-1] == '\r')
			p2--;
		/* skip empty line */
		if (p2 == p)
			break;
		len = p2 - p;
		if (len > sizeof(line) - 1)
			len = sizeof(line) - 1;
		umapi_memcpy(line, p, len);
		line[len] = '\0';
		parseLine(NULL, h, line, NULL, NULL);
		p = p1 + 1;
	}
//	h->contentLen = readIntByKey("Content-Length", h);
}
UM_VOID freeHttpHeaders(HttpHeaders *h)
{
	if(h->contentLen >0 && h->body)
		umapi_free(h->body);
	struct umapi_list_head *pos, *n;
	umapi_list_for_each_safe(pos,n,&h->h)
	{
		KV *kv = umapi_list_entry(pos,KV,h);
		umapi_list_del(&kv->h);
		if(kv->key)
			umapi_free(kv->key);
		if(kv->value)
			umapi_free(kv->value);
		umapi_free(kv);
	}		
	return ;
}
static UM_CHAR *findValueByKey(UM_CHAR *str, UM_CHAR *key, UM_CHAR *value)
{
	if(umapi_strncmp(str, key, umapi_strlen(key)) != 0)
		return UM_NULL;
	if(umapi_strlen(str) - umapi_strlen(key) <= 1)
		return UM_NULL;
	if(str[umapi_strlen(key)] != '=')
		return UM_NULL;
	UM_CHAR *pBuff = &str[umapi_strlen(key) + 1];
	UM_CHAR *pNextBuff = umapi_strstr(pBuff, "&");
	if(pNextBuff == UM_NULL)
		umapi_sprintf(value, "%s", pBuff);
	else
	{
		umapi_memcpy(value, pBuff, pNextBuff - pBuff);
		value[pNextBuff - pBuff] = '\0';
	}
	return value;
}
UM_CHAR * readStringByUrl(UM_CHAR *url, UM_CHAR *key, UM_CHAR *value)
{	
	UM_CHAR *ptmp = url;
	UM_CHAR *buf1;
	while(UM_TRUE)
	{		
		if(buf1 = findValueByKey(ptmp!= UM_NULL ? ptmp: url, key, value) != UM_NULL)
			return buf1;
		ptmp = umapi_strstr(ptmp, "&");
		if(ptmp != UM_NULL)
			ptmp++;
		else
			return UM_NULL;		
	}
}
UM_CHAR *getHttpParam(HttpHeaders *h, UM_CHAR *key, UM_CHAR *value)
{
	UM_CHAR *pBuff = umapi_strstr(h->url, "?");
	if(pBuff == UM_NULL)
		return readStringByKey(key, h, value);
	return readStringByUrl(++pBuff, key, value);
}
UM_CHAR* httpPackToString(UM_CHAR *httpHead, HttpHeaders *h)
{
	umapi_sprintf(httpHead, "%s %s %s\r\n",
		h->method,h->url,h->version);
	struct umapi_list_head *pos,*n;
	umapi_list_for_each_safe(pos,n,&h->h)
	{
		KV *kv = umapi_list_entry(pos,KV,h);
		umapi_sprintf(&httpHead[umapi_strlen(httpHead)], "%s: %s\r\n",
			kv->key, kv->value);
	}
	umapi_sprintf(&httpHead[umapi_strlen(httpHead)], "Content-Length %d\r\n",
			h->contentLen);
#if 0	
	if(h->contentLen > 0)
	{
		umapi_sprintf(&httpHead[umapi_strlen(httpHead)], "%s", h->body);
	}
#endif	
	return httpHead;
}
UM_S32 readHttpPack(UM_HANDLE fd, HttpHeaders *h)
{
	UM_CHAR httpBuffer[4096];
	UM_CHAR *pBuffer = &httpBuffer[0];
	umapi_list_create(&h->h);
	umapi_memset(httpBuffer, 0, 4096);
	UM_S32 recvlen;
	UM_U32 t = umapi_os_get_tick();
	while(1)
	{
NEXT:	
		if(umapi_os_get_tick() - t > 2000)
			break;
		recvlen = umapi_socket_recv(fd, pBuffer, 1, 0 );
		if(recvlen <=0)
		{
			if((errno == 11 || errno== 115) && recvlen < 0)
			{
				goto NEXT;
			}
			goto FAIL;
		}	
		pBuffer++;
		if ((pBuffer >= httpBuffer + 2 && !memcmp(pBuffer-2, "\n\n", 2)) ||
			(pBuffer >= httpBuffer + 4 && !memcmp(pBuffer-4, "\r\n\r\n", 4))) 
		{
			decBufferToHeaders(httpBuffer, h);
			return UM_SUCCESS;
		}
		if(pBuffer > httpBuffer + 4096)
		{
			break;
		}
	}
FAIL:
	LOGE("[%s.%d] httpBuffer:%s errno:%d\n", __FUNCTION__,__LINE__,httpBuffer,errno);
	return UM_FAILURE;
}
static UM_S32 readServerReply(UM_HANDLE fd, UM_VOID* param)
{
	UM_CHAR buff[1024] = {0};
	UM_CHAR *p = buff;
	UM_S32 ret;
	while(1)
	{
		ret = umapi_socket_recv(fd, p, 1, 0);
		if(ret == 0)
		{
			break;
		}
		else if(ret <0)
		{
			if (errno == 11)
				continue;
			break;
		}
		else
		{
			p++;
			if(p - buff >= 1023)
				break;
		}
	}
	LOGI("recv %s", buff);
	return UM_FAILURE;
}



UM_S32 sendNoFound(UM_HANDLE fd, UM_CHAR *serverName)
{
	return sendReply(fd, "HTTP/1.1 404 NOT FOUND\r\n"
			"Server: %s\r\n"
			"\r\n",
			serverName);
}

UM_S32 getChunkHead(UM_CHAR *pBuff, UM_CHAR *serverName)
{
	time_t ti;
	struct tm *tm;
	char buf2[40];
	ti = time(NULL);
	tm = gmtime(&ti);
	buf2[0] = '\0';
	strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S GMT", tm);
	umapi_sprintf(pBuff, "HTTP/1.1 200 OK\r\n"
			"Server: %s\r\n"
			"Date: %s\r\n"
			"Cache-Control: no-cache\r\n"
			"Content-Type: application/octet-stream\r\n"
			"Accept-Ranges: bytes\r\n"
			"Content-Range: bytes 0-\r\n"
			"Transfer-Encoding: chunked\r\n"
			"\r\n" ,serverName, buf2);
	return umapi_strlen(pBuff);
}

UM_S32 sendChunkHead(UM_HANDLE fd, UM_CHAR *serverName)
{
	time_t ti;
	struct tm *tm;
	char buf2[40];
	ti = time(NULL);
	tm = gmtime(&ti);
	buf2[0] = '\0';
	strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S GMT", tm);
	return sendReply(fd, 
			"HTTP/1.1 200 OK\r\n"
			"Server: %s\r\n"
			"Date: %s\r\n"
			"Cache-Control: no-cache\r\n"
			"Content-Type: application/octet-stream\r\n"
			"Accept-Ranges: bytes\r\n"
			"Content-Range: bytes 0-\r\n"
			"Transfer-Encoding: chunked\r\n"
			"\r\n" ,serverName, buf2);
}
UM_S32 sendChunkData(UM_HANDLE fd, UM_U8 *buff,UM_S32 bufflen)
{
	UM_S32 s32ret = 0;
#if 1
	UM_CHAR datalen[10];
	
	sprintf(datalen, "%x\r\n", bufflen);
	s32ret = umapi_socket_send(fd, datalen, umapi_strlen(datalen), 0);
	if(s32ret<=0 && (errno != EINPROGRESS && errno != 11))
		return UM_FAILURE;
	s32ret = umapi_socket_send(fd, buff, bufflen, 0);
	if(s32ret<=0 && (errno != EINPROGRESS && errno != 11))
		return UM_FAILURE;
	s32ret = umapi_socket_send(fd, "\r\n", umapi_strlen("\r\n"), 0);
	if(s32ret<=0 && (errno != EINPROGRESS && errno != 11))
		return UM_FAILURE;
#else
NEXTSEND:
	s32ret = umapi_socket_send(fd, buff - 6,  bufflen + 8, 0);
	if(s32ret <= 0)
	{
		if(errno == 11 && s32ret < 0)
		{
			goto NEXTSEND;
		}
		return UM_FAILURE;
	}
#endif
	return UM_SUCCESS;
}
UM_S32 decUrl(UM_CHAR * host, UM_S16 * port, UM_CHAR * path,UM_CHAR* url)
{
	UM_CHAR host2[40];
	UM_CHAR path2[100];
	av_url_split(NULL, 0, NULL, 0, host2, sizeof(host2), 
								port, path2, sizeof(path2), url);
	umapi_sprintf(host, "%s", host2);
	umapi_sprintf(path, "%s", path2);
	return UM_SUCCESS;
}

UM_HANDLE sink_accept_timed(UM_HANDLE fd, UMAPI_SOCKET_ADDR *pAddr, UM_S32 msecs)
{
	UMAPI_FD_SET rset;
	struct timeval tv;
	UM_S32 rc;
	do
	{
		umapi_socket_fd_bzero( &rset );
		umapi_socket_fd_set( fd, &rset );
	}
	while ( ( rc = umapi_socket_select( fd , &rset, NULL, NULL, msecs) ) == -1 && errno == EINTR );
	if(rc<1)
		return -1;
	return umapi_socket_accept(fd, pAddr);
}